/*
 * Copyright (c) 1990, 2022, shwfed and/or its affiliates. All rights reserved.
 *
 * @date: 2022-08-24
 *
 */
package cn.junglead.common.utils;

import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

/**
 * 密码学AES双向对称加密工具
 *
 * @author Gary.Wang
 * @version 1.0
 */
public final class CipherAesUtil extends CipherBase {

    /**
     * 默认的简单算法
     */
    private final static String ALGORITHMS = "AES/ECB/PKCS5Padding";
    private final static Logger logger = LoggerFactory.getLogger(CipherAesUtil.class);

    /**
     * ECB 模式的 AES 加密核心方法
     * @param key 加密密钥，字符长度为16位
     * @param plaintext 明文原文
     * @return 返回加密后的密文
     */
    public static byte[] encrypt(String key, String plaintext){
        try {
            Cipher cipher = Cipher.getInstance(ALGORITHMS);
            cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key.getBytes(), "AES"));
            return cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));
        } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) {
            logger.error("AES 加密发生异常，异常原因：{}", e.getMessage());
        }
        return new byte[0];
    }

    /**
     * 可自定义模式以及偏移量的 AES 核心加密方法
     *
     * @param algorithms 算法，例如：AES/CBC/PKCS5PADDING
     * @param ivValue iv向量值
     * @param key 密钥值
     * @param plaintext 待加密的明文
     * @return 返回加密后的字符数组
     */
    public static byte[] encrypt(String algorithms, String ivValue, String key, String plaintext){
        try {
            IvParameterSpec iv = new IvParameterSpec(ivValue.getBytes(StandardCharsets.UTF_8));
            SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "AES");

            Cipher cipher = Cipher.getInstance(algorithms);
            cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv);
            return cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));
        } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) {
            logger.error("AES 加密发生通用异常，异常原因：{}", e.getMessage());
        } catch (InvalidAlgorithmParameterException e) {
            logger.error("AES 加密发生 {} 异常，异常原因：{}", "InvalidAlgorithmParameterException", e.getMessage());
        }
        return new byte[0];
    }

    /**
     * ECB 模式的 AES 加密简单方法
     * @param outputFormat 返回格式，CipherAesUtil 类的静态属性
     * @param key 加密密钥
     * @param plaintext 明文原文
     * @return 返回加密后的结果
     */
    public static String encrypt(int outputFormat, String key, String plaintext){
        byte[] byteContent = encrypt(key, plaintext);
        if (outputFormat == FORMAT_HEX) {
            return Hex.encodeHexString(byteContent);
        }
        return Base64.getEncoder().encodeToString(byteContent);
    }

    /**
     * 可自定义模式以及偏移量的 AES 简单加密方法
     * @param algorithms 算法，例如：AES/CBC/PKCS5PADDING
     * @param ivValue iv向量值
     * @param outputFormat 返回格式，CipherAesUtil 类的静态属性
     * @param key 加密密钥
     * @param plaintext 明文原文
     * @return 返回加密后的结果
     */
    public static String encrypt(String algorithms, String ivValue, int outputFormat, String key, String plaintext){
        byte[] byteContent = encrypt(algorithms, ivValue, key, plaintext);
        if (outputFormat == FORMAT_HEX) {
            return Hex.encodeHexString(byteContent);
        }
        return Base64.getEncoder().encodeToString(byteContent);
    }

    /**
     * ECB 模式的 AES 解密核心方法
     * @param key 解密密钥，字符长度为16位
     * @param input 密文字符数组
     * @return 返回解密后的明文
     */
    public static byte[] decrypt(String key, byte[] input){
        try {
            Cipher cipher = Cipher.getInstance(ALGORITHMS);
            cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key.getBytes(), "AES"));
            return cipher.doFinal(input);
        } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) {
            logger.error("AES 解密发生异常，异常原因：{}", e.getMessage());
        }
        return new byte[0];
    }

    /**
     * 可自定义模式以及偏移量的 AES 核心解密方法
     *
     * @param algorithms 算法，例如：AES/CBC/PKCS5PADDING
     * @param ivValue iv向量值
     * @param key 密钥值
     * @param input 密文字符数组
     * @return 返回解密后的明文
     */
    public static byte[] decrypt(String algorithms, String ivValue, String key, byte[] input){
        try {
            IvParameterSpec iv = new IvParameterSpec(ivValue.getBytes(StandardCharsets.UTF_8));
            SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "AES");

            Cipher cipher = Cipher.getInstance(algorithms);
            cipher.init(Cipher.DECRYPT_MODE, keySpec, iv);
            return cipher.doFinal(input);
        } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) {
            logger.error("AES 加密发生通用异常，异常原因：{}", e.getMessage());
        } catch (InvalidAlgorithmParameterException e) {
            logger.error("AES 加密发生 {} 异常，异常原因：{}", "InvalidAlgorithmParameterException", e.getMessage());
        }
        return new byte[0];
    }



    /**
     * 可自定义模式以及偏移量的 AES 简单解密方法
     * @param inputFormat 输入格式， 为 CipherAesUtil 类的静态属性
     * @param key 加密密钥
     * @param ciphertext 密文
     * @return 返回解密后的结果
     */
    public static String decrypt(int inputFormat, String key, String ciphertext){
        byte[] input;
        if (inputFormat == FORMAT_HEX) {
            try {
                input = Hex.decodeHex(ciphertext.toCharArray());
            } catch (DecoderException e) {
                input = new byte[0];
                logger.error("AES 解密前的二进制转码发生异常，异常原因：{}", e.getMessage());
            }
        } else {
            input = Base64.getDecoder().decode(ciphertext);
        }
        if (input != null && input.length > 0){
            byte[] byteContent = decrypt(key, input);
            return new String(byteContent, StandardCharsets.UTF_8);
        }
        return null;
    }

    /**
     * 自定义使用的AES解密方法
     * @param algorithms 算法，例如：AES/CBC/PKCS7PADDING
     * @param ivValue iv向量值
     * @param inputFormat 输入格式， 为 CipherAesUtil 类的静态属性
     * @param key 加密密钥
     * @param ciphertext 密文
     * @return 返回解密后的结果
     */
    public static String decrypt(String algorithms, String ivValue, int inputFormat, String key, String ciphertext){
        byte[] input;
        if (inputFormat == FORMAT_HEX) {
            try {
                input = Hex.decodeHex(ciphertext.toCharArray());
            } catch (DecoderException e) {
                input = new byte[0];
                logger.error("AES 解密前的二进制转码发生异常，异常原因：{}", e.getMessage());
            }
        } else {
            input = Base64.getDecoder().decode(ciphertext);
        }
        if (input != null && input.length > 0){
            byte[] byteContent = decrypt(algorithms, ivValue, key, input);
            return new String(byteContent, StandardCharsets.UTF_8);
        }
        return null;
    }
}
